#ifndef APP_BASE_HPP
#define APP_BASE_HPP

#include "config.h"
#include "data/version.hpp"
#include "sql/sql_driver.hpp"
#include "dexode/EventBus.hpp"
#include "asio/io_context.hpp"
#include "asio/system_error.hpp"
#include "asio/post.hpp"

#include <memory>

using EventBus = std::shared_ptr<dexode::EventBus>;
using Listener = dexode::EventBus::Listener;

struct AppBaseData;
class DIARY_APP_SDK_API ApplicationBase
{
    AppBaseData* d;
public:
    ApplicationBase(ApplicationBase&&) = delete;
    ApplicationBase(const ApplicationBase&) = delete;
    ApplicationBase& operator=(const ApplicationBase&) = delete;
    ApplicationBase& operator=(ApplicationBase&&) = delete;

    EventBus Bus() const;

    virtual void ShowDialog(const std::string& name) const = 0;

    virtual ISqlDriver* Sql() const = 0;

    virtual void ShowStatusMessage(const std::string& msg, float timeout) const = 0;

    virtual void Exit() = 0;

    virtual void SetupSqlDriver() = 0;

    Version AppVersion() const;

    template<typename F>
    void Post(F&& f) { asio::post(GetMainIO(), std::forward<F>(f)); }

    template<typename F>
    void Async(F&& f) { asio::post(GetTaskIO(), std::forward<F>(f)); }

    static ApplicationBase* Instance();
protected:
    ApplicationBase(Version app_version);
    virtual ~ApplicationBase();

    asio::io_context& GetMainIO() const;
    asio::io_context& GetTaskIO() const;
};

#define App (ApplicationBase::Instance())

#endif // APP_BASE_HPP
